package com.smart.community.commons.log;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * 智慧社区管理系统 - 结构化日志工具类
 * 
 * @author Wu.Liang
 * @date 2024-12-20
 * @version 1.0.0
 * @description 提供结构化的业务日志记录功能，便于日志分析和监控
 * @task 002_Step9_Subtask4_Logging_Configuration_Optimization
 */
@Component
public class StructuredLogger {
    
    private static final Logger logger = LoggerFactory.getLogger(StructuredLogger.class);
    private final ObjectMapper objectMapper = new ObjectMapper();
    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    
    /**
     * 记录业务操作日志
     * 
     * @param module  模块名称
     * @param action  操作名称
     * @param userId  用户ID
     * @param details 操作详情
     * @param context 上下文信息
     * @param result  操作结果
     */
    public void logBusinessOperation(String module, String action, String userId, String details,
                                          Map<String, Object> context, Object result) {
        Map<String, Object> logData = new HashMap<>();
        logData.put("logType", "BUSINESS_OPERATION");
        logData.put("timestamp", LocalDateTime.now().format(DATETIME_FORMATTER));
        logData.put("module", module);
        logData.put("action", action);
        logData.put("userId", userId);
        logData.put("details", details);
        logData.put("context", context);
        logData.put("result", result != null ? "SUCCESS" : "FAIL");
        logData.put("traceId", MDC.get("traceId"));
        logData.put("clientIp", MDC.get("clientIp"));
        logData.put("requestMethod", MDC.get("requestMethod"));
        logData.put("requestUri", MDC.get("requestUri"));
        
        if ("SUCCESS".equals(result)) {
            logger.info("业务操作: {}", toJsonString(logData));
        } else {
            logger.warn("业务操作失败: {}", toJsonString(logData));
        }
    }
    
    /**
     * 记录数据库操作日志
     * 
     * @param operation     操作类型（INSERT, UPDATE, DELETE, SELECT）
     * @param tableName     表名
     * @param executionTime 执行时间（毫秒）
     * @param sql           SQL语句
     * @param result        操作结果
     */
    public void logDatabaseOperation(String operation, String tableName, long executionTime, String sql,
                                          String result) {
        Map<String, Object> logData = new HashMap<>();
        logData.put("logType", "DATABASE_OPERATION");
        logData.put("timestamp", LocalDateTime.now().format(DATETIME_FORMATTER));
        logData.put("operation", operation);
        logData.put("tableName", tableName);
        logData.put("executionTime", executionTime);
        logData.put("sql", sql);
        logData.put("result", result);
        logData.put("traceId", MDC.get("traceId"));
        
        // 慢查询标记
        if (executionTime > 1000) {
            logData.put("slowQuery", true);
            logger.warn("慢查询检测: {}", toJsonString(logData));
        } else {
            logData.put("slowQuery", false);
            logger.info("数据库操作: {}", toJsonString(logData));
        }
    }
    
    /**
     * 记录缓存操作日志
     * 
     * @param operation     操作类型（GET, SET, DELETE, EXPIRE）
     * @param key           缓存键
     * @param hit           是否命中（仅对GET操作有效）
     * @param executionTime 执行时间（毫秒）
     * @param result        操作结果
     */
    public void logCacheOperation(String operation, String key, Boolean hit, long executionTime, Object result) {
        Map<String, Object> logData = new HashMap<>();
        logData.put("logType", "CACHE_OPERATION");
        logData.put("timestamp", LocalDateTime.now().format(DATETIME_FORMATTER));
        logData.put("operation", operation);
        logData.put("key", key);
        logData.put("hit", hit);
        logData.put("executionTime", executionTime);
        logData.put("result", result);
        logData.put("traceId", MDC.get("traceId"));
        
        // 缓存未命中或执行时间过长的情况
        if (Boolean.FALSE.equals(hit) || executionTime > 100) {
            logger.warn("缓存性能问题: {}", toJsonString(logData));
        } else {
            logger.info("缓存操作: {}", toJsonString(logData));
        }
    }
    
    /**
     * 记录性能监控日志
     * 
     * @param monitorType 监控类型
     * @param metricName  指标名称
     * @param metricValue 指标值
     * @param threshold   阈值
     * @param unit        单位
     */
    public void logPerformanceMetric(String monitorType, String metricName, Object metricValue, Object threshold,
                                          String unit) {
        Map<String, Object> logData = new HashMap<>();
        logData.put("logType", "PERFORMANCE_METRIC");
        logData.put("timestamp", LocalDateTime.now().format(DATETIME_FORMATTER));
        logData.put("monitorType", monitorType);
        logData.put("metricName", metricName);
        logData.put("metricValue", metricValue);
        logData.put("threshold", threshold);
        logData.put("unit", unit);
        logData.put("traceId", MDC.get("traceId"));
        
        // 判断是否超过阈值
        boolean exceedsThreshold = compareMetricValue(metricValue, threshold);
        logData.put("exceedsThreshold", exceedsThreshold);
        
        if (exceedsThreshold) {
            logger.warn("性能指标告警: {}", toJsonString(logData));
        } else {
            logger.info("性能指标: {}", toJsonString(logData));
        }
    }
    
    /**
     * 记录错误日志
     * 
     * @param errorType    错误类型
     * @param errorMessage 错误消息
     * @param exception    异常对象
     */
    public void logError(String errorType, String errorMessage, Throwable exception) {
        Map<String, Object> logData = new HashMap<>();
        logData.put("logType", "ERROR");
        logData.put("timestamp", LocalDateTime.now().format(DATETIME_FORMATTER));
        logData.put("errorType", errorType);
        logData.put("errorMessage", errorMessage);
        logData.put("exceptionClass", exception != null ? exception.getClass().getSimpleName() : null);
        logData.put("stackTrace", exception != null ? getSimpleStackTrace(exception) : null);
        logData.put("traceId", MDC.get("traceId"));
        logData.put("clientIp", MDC.get("clientIp"));
        logData.put("requestMethod", MDC.get("requestMethod"));
        logData.put("requestUri", MDC.get("requestUri"));
        
        if (exception == null) {
            logger.error("系统错误: {}", toJsonString(logData));
        } else {
            logger.error("系统错误: {}", toJsonString(logData), exception);
        }
    }
    
    /**
     * 比较指标值与阈值
     * 
     * @param metricValue 指标值
     * @param threshold   阈值
     * @return 是否超过阈值
     */
    private boolean compareMetricValue(Object metricValue, Object threshold) {
        if (metricValue == null || threshold == null) {
            return false;
        }
        
        try {
            if (metricValue instanceof Number && threshold instanceof Number) {
                double value = ((Number) metricValue).doubleValue();
                double limit = ((Number) threshold).doubleValue();
                return value > limit;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.warn("比较指标值失败: metricValue={}, threshold={}", metricValue, threshold, e);
            return false;
        }
    }
    
    /**
     * 获取简化的堆栈跟踪信息
     * 
     * @param exception 异常对象
     * @return 简化的堆栈跟踪信息
     */
    private static String getSimpleStackTrace(Throwable exception) {
        if (exception == null) {
            return null;
        }
        
        StringBuilder sb = new StringBuilder();
        StackTraceElement[] elements = exception.getStackTrace();
        int maxElements = Math.min(elements.length, 5); // 只取前5行
        
        for (int i = 0; i < maxElements; i++) {
            StackTraceElement element = elements[i];
            sb.append(element.getClassName())
              .append(".")
              .append(element.getMethodName())
              .append("(")
              .append(element.getFileName())
              .append(":")
              .append(element.getLineNumber())
              .append(")");
            
            if (i < maxElements - 1) {
                sb.append(" -> ");
            }
        }
        
        return sb.toString();
    }
    
    /**
     * 将对象转换为JSON字符串
     * 
     * @param obj 要转换的对象
     * @return JSON字符串
     */
    private String toJsonString(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.warn("JSON序列化失败: {}", obj, e);
            return obj != null ? obj.toString() : "null";
        }
    }
}
